import logging
from typing import Optional, Union, Text, Any, Dict

from rasa.core.domain import Domain
from rasa.utils import common
from rasa.utils.endpoints import EndpointConfig
from rasa.core.trackers import DialogueStateTracker

logger = logging.getLogger(__name__)


class NaturalLanguageGenerator:
    """基于对话状态生成机器人话语。"""

    async def generate(
        self,
        template_name: Text,
        tracker: "DialogueStateTracker",
        output_channel: Text,
        **kwargs: Any,
    ) -> Optional[Dict[Text, Any]]:
        """
        为请求的模板生成响应。

        实现这一点有很多不同的方法，例如，生成可以基于模板，也可以完全基于ML，将对话状态输入机器学习NLG模型。"""
        raise NotImplementedError

    @staticmethod
    def create(
        obj: Union["NaturalLanguageGenerator", EndpointConfig, None],
        domain: Optional[Domain],
    ) -> "NaturalLanguageGenerator":
        """创建生成器的工厂。"""

        if isinstance(obj, NaturalLanguageGenerator):
            return obj
        else:
            return _create_from_endpoint_config(obj, domain)


def _create_from_endpoint_config(
        endpoint_config: Optional[EndpointConfig] = None,
        domain: Optional[Domain] = None
) -> "NaturalLanguageGenerator":
    """给定一个端点配置对象，创建一个合适的NLG对象。"""

    domain = domain or Domain.empty()

    if endpoint_config is None:
        from rasa.core.nlg import (  # pytype: disable=pyi-error
            TemplatedNaturalLanguageGenerator,
        )
        # 如果未设置端点配置，则这是默认类型
        nlg = TemplatedNaturalLanguageGenerator(domain.templates)

    elif endpoint_config.type is None or endpoint_config.type.lower() == "callback":
        from rasa.core.nlg import (  # pytype: disable=pyi-error
            CallbackNaturalLanguageGenerator,
        )
        # 如果未设置nlg类型，则为默认类型
        nlg = CallbackNaturalLanguageGenerator(endpoint_config=endpoint_config)

    elif endpoint_config.type.lower() == "template":
        from rasa.core.nlg import (  # pytype: disable=pyi-error
            TemplatedNaturalLanguageGenerator,
        )
        nlg = TemplatedNaturalLanguageGenerator(domain.templates)

    else:
        nlg = _load_from_module_string(endpoint_config, domain)

    logger.debug(f"Instantiated NLG to '{nlg.__class__.__name__}'.")
    return nlg


def _load_from_module_string(
    endpoint_config: EndpointConfig, domain: Domain
) -> "NaturalLanguageGenerator":
    """初始化自定义自然语言生成器。

    Args:
        domain:             定义助手操作的域范围
        endpoint_config:    特定的自然语言生成器
    """

    try:
        nlg_class = common.class_from_module_path(endpoint_config.type)
        return nlg_class(endpoint_config=endpoint_config, domain=domain)
    except (AttributeError, ImportError) as e:
        raise Exception(
            f"Could not find a class based on the module path "
            f"'{endpoint_config.type}'. Failed to create a "
            f"`NaturalLanguageGenerator` instance. Error: {e}"
        )
